package kaist.sep502.tsp.view;

import java.util.ArrayList;
import java.util.List;

import kaist.sep502.tsp.Activator;
import kaist.sep502.tsp.NavigationView;
import kaist.sep502.tsp.model.City;
import kaist.sep502.tsp.model.Problem;
import kaist.sep502.tsp.model.Solution;
import kaist.sep502.tsp.util.TspUtil;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.zest.core.widgets.Graph;
import org.eclipse.zest.core.widgets.GraphConnection;
import org.eclipse.zest.core.widgets.GraphNode;
import org.eclipse.zest.core.widgets.ZestStyles;
import org.eclipse.zest.layouts.LayoutEntity;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
import org.eclipse.zest.layouts.dataStructures.InternalNode;
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;

public class CityMapView extends ViewPart{
	public static final String ID = "kaist.sep502.tsp.view.citymapview";
	private Graph graph;
	private int layout = 1;
	public static int instanceNum = 0;
	private List<City> cityList;
	private List<GraphNode> gNodeList;
	private Solution solution;
	private ISelectionListener pageSelectionListener;
	private Rectangle rect;

	public CityMapView() {
	}
	
	public void initCityMap(Problem problem){
		this.cityList = problem.cityList;
		
		// 비율 계산
		Rectangle rect = graph.getBounds();
		
		gNodeList = new ArrayList<GraphNode>();
		GraphNode gNode;
		double x, y;
		for(int i=0; i<cityList.size(); i++){
			x = TspUtil.getScreenPoint(rect.width, getCity(i).getX());
			y = TspUtil.getScreenPoint(rect.height, getCity(i).getY());
			gNode = new GraphNode(graph, SWT.NONE, "" + i);
			gNode.setLocation(x, y);
			gNodeList.add(gNode);
		}
		
		graph.layout(true);
		
		
	}
	
	/**
	 * @param tourHistory
	 */
	public void drawConnection(Solution solution) {
		this.solution = solution;
		int fromNode = solution.goalCityPath.tourHistory.get(0);
		int toNode = 0;
		for(int i=1; i<solution.goalCityPath.tourHistory.size();i++){
			toNode = solution.goalCityPath.tourHistory.get(i);
			new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, gNodeList.get(fromNode), gNodeList.get(toNode));
			fromNode = toNode;
		}
		
		gNodeList.get(solution.goalCityPath.tourHistory.get(0)).highlight();
	}
	
	public City getCity(int cityNo){
		for(int i=0; i<cityList.size(); i++){
			if(cityList.get(i).getCityNo() == cityNo){
				return cityList.get(i);
			}
		}
		
		return null;
	}
	
	@Override
	public void createPartControl(Composite parent) {
		graph = new Graph(parent, SWT.NONE);
		
		graph.setLayoutAlgorithm(new AbstractLayoutAlgorithm(LayoutStyles.NONE){

			@Override
			public void setLayoutArea(double x, double y, double width, double height) {
			}

			@Override
			protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
				return true;
			}

			@Override
			protected void applyLayoutInternal(InternalNode[] entitiesToLayout,
					InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY,
					double boundsWidth, double boundsHeight) {
				if(cityList == null) return;
				
				fireProgressStarted(0);
				for(int i=0; i<entitiesToLayout.length; i++){
					LayoutEntity layoutEntity = entitiesToLayout[i].getLayoutEntity();
					
					double x = TspUtil.getScreenPoint(boundsWidth, getCity(i).getX());
					double y = TspUtil.getScreenPoint(boundsHeight, getCity(i).getY());
					layoutEntity.setLocationInLayout(x, y);
				}
				fireProgressEnded(0);
			}

			@Override
			protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout,
					InternalRelationship[] relationshipsToConsider, double x, double y,
					double width, double height) {
			}

			@Override
			protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout,
					InternalRelationship[] relationshipsToConsider) {
			}

			@Override
			protected int getTotalNumberOfLayoutSteps() {
				// TODO Auto-generated method stub
				return 0;
			}

			@Override
			protected int getCurrentLayoutStep() {
				// TODO Auto-generated method stub
				return 0;
			}
			
		}, true);
		
		
		graph.addFocusListener(new FocusListener() {
			
			@Override
			public void focusLost(FocusEvent e) {
			}
			
			@Override
			public void focusGained(FocusEvent e) {
				changeInformation();
			}
		});
		
		// 이벤트 리스너 등록.
		hookPageSelection();
		
		final Shell shell = parent.getShell(); 
		parent.getShell().addListener(SWT.RESIZE, new Listener(){
			@Override
			public void handleEvent(Event event) {
				rect = shell.getClientArea();
				graph.setBounds(rect);
				graph.pack();
				graph.update();
				System.out.println("111111111");
			}
		});
	}
	
	private void hookPageSelection(){
		pageSelectionListener = new ISelectionListener() {
			
			@Override
			public void selectionChanged(IWorkbenchPart part, ISelection selection) {
				pageSelectionChanged(part, selection);
			}
		};
		
		getSite().getPage().addPostSelectionListener(pageSelectionListener);
	}
	
	protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection){
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}
	
	public void setLayoutManager() {
		switch (layout){
		case 1:
				graph.setLayoutAlgorithm(new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
				layout++;
				break;
		case 2:
				graph.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
				layout = 1;
				break;
		}
	}
	
	
	
	private void changeInformation(){
		NavigationView navView;
		IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 
		if(window != null) {	
			try {
				navView = (NavigationView) window.getActivePage().showView(NavigationView.ID);
				if(navView != null && solution != null){
					navView.addResultMessage(solution);
				}
			} catch (PartInitException e) {
				Activator.log(e);
				e.printStackTrace();
			}
		}
	}
	
	public void setStatusLine(String message){
		IActionBars bars = getViewSite().getActionBars();
		bars.getStatusLineManager().setMessage(message);
	}

	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
	 */
	@Override
	public void dispose() {
		if(graph != null && graph.isDisposed() == false){
			graph.dispose();
		}
		getSite().getPage().removePostSelectionListener(pageSelectionListener);
		super.dispose();
	}
}
